using System;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Xml.Serialization;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;

namespace Core.Graphics
{
    [Serializable()]
    [XmlRoot("Tile")]
    public class Tile
    {
        public static int TileHeight = 32;
        public static int TileWidth = 32;

        public static int ScaledTileHeight = 32;
        public static int ScaledTileWidth = 32;

        [XmlElement("SpriteID")]
        public virtual TileID SpriteID { get { return _ID; } set { _ID = value; } }
        public virtual Color DrawColor { get { return _DrawColor; } set { _DrawColor = value; } }
        public virtual TileSetTile TileSetTile { 
            get {
                if (_TileSetTile == null)
                {
                    _TileSetTile = TileSetCollection.GetTile(SpriteID, TileSetTypes.Terrain);
                }

                return _TileSetTile; 
            } 
            set { _TileSetTile = value; } }

        protected TileID _ID = TileID.EmptyID;
        protected Color _DrawColor = Color.White;
        protected TileSetTile _TileSetTile = null;

        public Tile(TileID ID)
        {
            _ID = ID;
        }

        public Tile() { /*For XML Serialization */ }

        public virtual void Draw(SpriteBatch SpriteBatch, Rectangle Destination)
        {
            //Draw sprite with 0 rotation
            Draw(SpriteBatch, Destination, 0f);
        }

        public virtual void Draw(SpriteBatch SpriteBatch, Rectangle Destination, float Rotation)
        {
            //Draw the tile using the sprite batch at the destination rectangle
            SpriteBatch.Draw(TileSetTile.Parent.TileSetTexture,
                                         Destination, TileSetTile.SourceRectangle,
                                         DrawColor, Rotation, Vector2.Zero, SpriteEffects.None, 0);
        }

        #region StaticsAndHelpers
        private static Tile _BlankTile = new Tile(TileID.EmptyID);

        public static Tile BlankTile
        {
            get { return _BlankTile; } 
        }

        private static Tile _NonExistant = new Tile(new TileID(-2, -2));

        public static Tile NonExistant
        {
            get { return _NonExistant; }
        }

        public static bool operator ==(Tile x, Tile y)
        {
            return x.SpriteID.ID == y.SpriteID.ID && x.SpriteID.TileSetID == y.SpriteID.TileSetID;
        }

        public static bool operator !=(Tile x, Tile y)
        {
            return x.SpriteID.ID != y.SpriteID.ID && x.SpriteID.TileSetID != y.SpriteID.TileSetID;
        }

        public override bool Equals(object obj)
        {
            return base.Equals(obj);
        }

        public override int GetHashCode()
        {
            return _ID.ID.GetHashCode() + _ID.TileSetID.GetHashCode();
        }

        protected static BitVector32.Section bvsTileSet = BitVector32.CreateSection(1000);
        protected static BitVector32.Section bvsTile = BitVector32.CreateSection(2000, bvsTileSet);

        public static int GetTileAsBitVector(Tile Tile)
        {
            BitVector32 bvTile = new BitVector32(0);

            bvTile[bvsTileSet] = Tile.SpriteID.TileSetID;
            bvTile[bvsTile] = Tile.SpriteID.ID;

            return bvTile.Data;
        }

        public static Tile GetTileFromBitVector(int Data)
        {
            BitVector32 bvTile = new BitVector32(Data);

            return new Tile(new TileID(bvTile[bvsTile], bvTile[bvsTileSet]));
        }
        #endregion
    }

    [Serializable()]
    public class TileCollection : Collection<Tile>
    {
        public Tile GetTileByID(TileID ID)
        {
            foreach (Tile t in this)
            {
                if (t.SpriteID == ID)
                    return t;
            }

            return null;
        }

        public static TileCollection GetTilesForEmptyTileLayer(int Width, int Height)
        {
            TileCollection tc = new TileCollection();
            
            for (int x = 0; x < Width * Height; x++)
            {
                tc.Add(Tile.BlankTile);
            }

            return tc;
        }

        #region IXmlSerializable Members

        public System.Xml.Schema.XmlSchema GetSchema()
        {
            //not implemented, from what I've read this is only used by DataSets
            return null;
        }

        #endregion
    }
}
